package com.hx.template.jdbc.jdbcTemplate;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author Huathy
 * @date 2021-09-02 22:51
 * @description
 */
public abstract class JdbcTemplate {
    private DataSource dataSource;

    public JdbcTemplate(DataSource dataSource){
        this.dataSource = dataSource;
    }

    public List<?> query(String sql, RowMapper<?> rowMapper, Object[] values){
        try {
            // 1. 获取连接
            Connection conn = this.getConnection();
            // 2. 创建语句集
            PreparedStatement pstm = this.createPrepareStatement(conn,sql);
            // 3. 执行SQL
            ResultSet rs = this.executeQuery(pstm,values);
            // 4. 处理结果集
            List<?> result = this.paresResultSet(rs,rowMapper);
            // 5. 关闭资源
            this.closeResource(rs,pstm,conn);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

    private void closeResource(ResultSet rs, PreparedStatement pstm, Connection conn) throws SQLException {
        if ( rs != null ){
            rs.close();
        }
        if( pstm != null ){
            pstm.close();
        }
        if( conn != null ){
            conn.close();
        }
    }

    protected List<?> paresResultSet(ResultSet rs, RowMapper<?> rowMapper) throws Exception {
        List<Object> result = new ArrayList<>();
        if( rs != null ){
            int rowNum = 1;
            while (rs.next()){
                result.add(rowMapper.mapRow(rs,rowNum++));
            }
        }
        return result;
    }

    private ResultSet executeQuery(PreparedStatement pstm, Object[] values) throws SQLException {
        for (int i = 0; i < values.length; i++) {
            pstm.setObject(i,values[i]);
        }
        return pstm.executeQuery();
    }

    private PreparedStatement createPrepareStatement(Connection conn, String sql) throws SQLException {
        return conn.prepareStatement(sql);
    }

    private Connection getConnection() throws SQLException {
        return this.dataSource.getConnection();
    }
}
